package com.dmai.capacity.platform.user.service.impl;

import com.dmai.capacity.platform.common.constant.CodeEnum;
import com.dmai.capacity.platform.common.constant.CommonConstant;
import com.dmai.capacity.platform.common.constant.UserTypeEnum;
import com.dmai.capacity.platform.common.context.TenantContextHolder;
import com.dmai.capacity.platform.common.dto.PageResult;
import com.dmai.capacity.platform.common.dto.PageResultData;
import com.dmai.capacity.platform.common.exception.BusinessException;
import com.dmai.capacity.platform.common.model.LoginAppUser;
import com.dmai.capacity.platform.common.model.SysRole;
import com.dmai.capacity.platform.common.model.SysUser;
import com.dmai.capacity.platform.constants.ExceptionEnum;
import com.dmai.capacity.platform.constants.InstitutionAuthStateEnum;
import com.dmai.capacity.platform.constants.RoleTypeEnum;
import com.dmai.capacity.platform.log.trace.MDCTraceUtils;
import com.dmai.capacity.platform.oauth.common.util.AuthUtils;
import com.dmai.capacity.platform.oauth.service.ITokensService;
import com.dmai.capacity.platform.user.mapper.SysInstitutionDao;
import com.dmai.capacity.platform.user.model.SysInstitution;
import com.dmai.capacity.platform.user.model.SysOrganization;
import com.dmai.capacity.platform.user.model.SysScopePermission;
import com.dmai.capacity.platform.user.pojo.request.InstitutionRegisterAgainRequest;
import com.dmai.capacity.platform.user.pojo.request.InstitutionRegisterRequest;
import com.dmai.capacity.platform.user.pojo.response.InstitutionVO;
import com.dmai.capacity.platform.user.service.*;
import com.dmai.capacity.platform.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.apache.commons.collections4.MapUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

@Slf4j
@Service
public class SysInstitutionServiceImpl implements ISysInstitutionService {

    @Autowired
    private SysInstitutionDao institutionDao;

    @Autowired
    private ISysOrganizationService organizationService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysAreaService areaService;

    @Autowired
    private ISysScopePermissionService scopePermissionService;

    @Autowired
    private ITokensService tokensService;

    @Autowired
    private IEmailService emailService;

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private TaskExecutor taskExecutor;


    /**
     * 机构注册
     *
     * @param item
     */
    @Override
    @Transactional
    public synchronized int register(InstitutionRegisterRequest item) {


        // 两次密码是否一致
        if (!item.getAdminPassword().equals(item.getAdminPasswordConfirm())) {
            throw new BusinessException(ExceptionEnum.PASSWORD_NOT_MATCH.getCode(), ExceptionEnum.PASSWORD_NOT_MATCH.getMsg());
        }

        verify(item);

        // 管理员账号是否重复
        SysInstitution orig = institutionDao.findByAdminAccount(item.getAdminAccount());
        if (orig != null && (item.getId() == null || item.getId().equals(orig.getId()))) {
            throw new BusinessException(ExceptionEnum.ACCOUNT_EXIST.getCode(), ExceptionEnum.ACCOUNT_EXIST.getMsg());
        }
        // 登录账号是否存在
        SysUser user = userService.selectByUsername(item.getAdminAccount());
        if (user != null) {
            throw new BusinessException(ExceptionEnum.ACCOUNT_EXIST.getCode(), ExceptionEnum.ACCOUNT_EXIST.getMsg());
        }


        int r = 0;
        if (item.getId() == null) {
            SysInstitution model = new SysInstitution();
            BeanUtils.copyProperties(item, model);
            model.setId(MDCTraceUtils.createTraceId().toString());
            model.setCode(StringUtil.getNextSequence(institutionDao.findMaxCode(item.getExamVenue()), 4));
            model.setOrgRegAreaName(areaService.getFullName(model.getOrgRegArea()));
            model.setOrgTeachingAreaName(areaService.getFullName(model.getOrgTeachingArea()));
            model.setAdminPassword(passwordEncoder.encode(item.getAdminPassword()));
            model.setAuthState(InstitutionAuthStateEnum.SUBMIT.getCode());
            model.setRegisterTime(new Date());
            model.setUpdateTime(new Date());
            model.setTenantId(AuthUtils.getTenant());
            r = institutionDao.save(model);
        } else {
            SysInstitution model = institutionDao.findById(item.getId());
            Assert.notNull(model, "机构不存在");
            if (!InstitutionAuthStateEnum.REJECT.getCode().equals(model.getAuthState())) {
                throw new BusinessException(ExceptionEnum.ILLEGAL_AUTH_STATE.getCode(), ExceptionEnum.ILLEGAL_AUTH_STATE.getMsg());
            }
            BeanUtils.copyProperties(item, model);
            model.setOrgRegAreaName(areaService.getFullName(model.getOrgRegArea()));
            model.setOrgTeachingAreaName(areaService.getFullName(model.getOrgTeachingArea()));
            model.setAdminPassword(passwordEncoder.encode(item.getAdminPassword()));
            model.setAuthState(InstitutionAuthStateEnum.SUBMIT.getCode());
            model.setUpdateTime(new Date());
            r = institutionDao.update(model);
        }
        return r;
    }

    @Override
    public int registerAgain(InstitutionRegisterAgainRequest item) {

        verify(item);

        int r = 0;

        SysInstitution model = institutionDao.findById(item.getId());
        Assert.notNull(model, "机构不存在");
        if (!InstitutionAuthStateEnum.REJECT.getCode().equals(model.getAuthState())) {
            throw new BusinessException(ExceptionEnum.ILLEGAL_AUTH_STATE.getCode(), ExceptionEnum.ILLEGAL_AUTH_STATE.getMsg());
        }
        BeanUtils.copyProperties(item, model);
        model.setOrgRegAreaName(areaService.getFullName(model.getOrgRegArea()));
        model.setOrgTeachingAreaName(areaService.getFullName(model.getOrgTeachingArea()));
        model.setAuthState(InstitutionAuthStateEnum.SUBMIT.getCode());
        model.setUpdateTime(new Date());
        r = institutionDao.update(model);

        return r;
    }

    @Override
    @Transactional
    public int auth(Long id, Integer authState, String remark) {
        LoginAppUser currentUser = AuthUtils.getLoginAppUser();
        String tenantId = AuthUtils.getTenant();

        SysInstitution orig = institutionDao.findById(id);
        Assert.notNull(orig, "机构不存在");

        if (authState.equals(InstitutionAuthStateEnum.PASS.getCode())) {
            orig.setAuthState(InstitutionAuthStateEnum.PASS.getCode());
        } else if (authState.equals(InstitutionAuthStateEnum.REJECT.getCode())) {
            if (orig.getAuthState() != null && orig.getAuthState().equals(InstitutionAuthStateEnum.PASS.getCode())) {
                throw new BusinessException(ExceptionEnum.FORBIT_REJECT.getCode(), ExceptionEnum.FORBIT_REJECT.getMsg());
            }
            orig.setAuthState(InstitutionAuthStateEnum.REJECT.getCode());
        } else {
            throw new IllegalArgumentException("非法参数");
        }
        orig.setAuthTime(new Date());
        orig.setAuthUserid(currentUser.getId());
        orig.setAuthUsername(currentUser.getRealname());
        orig.setAuthRemark(remark);
        orig.setTenantId(tenantId);

        // 增加机构管理员登录用户
        if (authState.equals(InstitutionAuthStateEnum.PASS.getCode())) {
            SysUser user = userService.selectByUserid(orig.getAdminUserid());
            if (user == null) {
                user = new SysUser();
                user.setId(Long.valueOf(MDCTraceUtils.createTraceId()));
                user.setUsername(orig.getAdminAccount());
                user.setPassword(orig.getAdminPassword());
                user.setRealname(orig.getName());
                user.setMobile(orig.getContactMobile());
                user.setEmail(orig.getContactEmail());
                user.setOrganizationId(orig.getId());
                user.setType(UserTypeEnum.INSTITUTION.getCode());
                user.setTenantId(tenantId);

                SysRole role = roleService.findByCode(RoleTypeEnum.INSTITUTION.getCode());
                user.setRoleIds(role == null ? "" : role.getId().toString());

                orig.setAdminUserid(user.getId());

                userService.save(user);
            } else {
                user.setUsername(orig.getAdminAccount());
                user.setPassword(orig.getAdminPassword());
                user.setRealname(orig.getName());
                user.setMobile(orig.getContactMobile());
                user.setEmail(orig.getContactEmail());
                user.setOrganizationId(orig.getId());
                user.setType(UserTypeEnum.INSTITUTION.getCode());
                user.setEnabled(true);
                user.setStatus(1);
                userService.update(user);
            }
        } else if (authState.equals(InstitutionAuthStateEnum.REJECT.getCode())) { //驳回，禁用管理员账户
            SysUser user = userService.selectByUserid(orig.getAdminUserid());
            if (user != null) {
                // 1. 将用户状态改为禁用
                userService.updateEnabled(user.getId(), false);

                // 2. 踢出用户登录状态
                try {
                    tokensService.kickOutUser(user.getUsername(), user.getTenantId());
                } catch (Exception e) {
                    log.error("踢出用户异常:{}", e.toString());
                }
            }
        }

        int r = institutionDao.updateAuth(orig);

        // 发送审核通知邮件
        CompletableFuture.runAsync(() -> {
            sendEmail(orig);
        }, taskExecutor);

        return r;
    }

    //审批通过给机构发邮件
    private void sendEmail(SysInstitution target) {
        log.info("开始发送注册审核通知邮件：{}...", target.getContactEmail());
        Context context = new Context();
        context.setVariable("authResult", target.getAuthState().equals(InstitutionAuthStateEnum.PASS.getCode()) ? "已经通过审核" : "被驳回");
        String content = templateEngine.process("mail_auth_template.html", context);
        emailService.sendHtml(TenantContextHolder.getTenant(), target.getContactEmail(), "【考级考务管理系统】审核结果通知", content);
        log.info("发送注册审核通知邮件成功...");
    }

    /**
     * 修改
     *
     * @param item
     */
    public int update(SysInstitution item) {
        item.setUpdateTime(new Date());
        return institutionDao.update(item);
    }

    /**
     * 参数校验
     */
    private void verify(InstitutionRegisterAgainRequest item) {
        if (StringUtils.isEmpty(AuthUtils.getTenant())) {
            throw new BusinessException(ExceptionEnum.COMMON.getCode(), ExceptionEnum.COMMON.getMsg());
        }
        // 名称是否重复
        SysInstitution orig = institutionDao.findByName(item.getName());
        if (orig != null && (item.getId() == null || item.getId().equals(orig.getId()))) {
            throw new BusinessException(ExceptionEnum.DATA_EXISTS.getCode(), ExceptionEnum.DATA_EXISTS.getMsg());
        }
        // 社会统一信用代码是否重复
        orig = institutionDao.findByUscc(item.getUscc());
        if (orig != null && (item.getId() == null || item.getId().equals(orig.getId()))) {
            throw new BusinessException(ExceptionEnum.DATA_EXISTS.getCode(), ExceptionEnum.DATA_EXISTS.getMsg());
        }
        // 考区是否非法
        SysOrganization org = organizationService.findById(item.getExamVenue());
        if (org == null) {
            throw new BusinessException(ExceptionEnum.COMMON.getCode(), "考区不存在");
        }
    }


    /**
     * 删除
     *
     * @param id
     */
    public int delete(Long id) {
        SysInstitution orig = institutionDao.findById(id);
        if (orig == null) {
            throw new IllegalArgumentException("找不到对应的数据");
        }
        return institutionDao.delete(id);
    }

    /**
     * 查询记录
     *
     * @param id
     * @return
     */
    public InstitutionVO findById(Long id) {
        InstitutionVO result = new InstitutionVO();
        SysInstitution model = institutionDao.findById(id);
        BeanUtils.copyProperties(model, result);

        result.setExamVenueName(organizationService.getFullName(result.getExamVenue()));

        return result;
    }

    @Override
    public InstitutionVO findByAccount(String adminAccount, String password, boolean check) {
        SysInstitution model = institutionDao.findByAdminAccount(adminAccount);
        if (model == null) {
            return null;
        }
        if (!passwordEncoder.matches(password, model.getAdminPassword())) {
            return null;
        }
        if (check) {
            if (model.getAuthState().equals(InstitutionAuthStateEnum.SUBMIT.getCode())) {
                throw new BusinessException(ExceptionEnum.LOGIN_AUTHING.getCode(), ExceptionEnum.LOGIN_AUTHING.getMsg());
            }
            if (model.getAuthState().equals(InstitutionAuthStateEnum.REJECT.getCode())) {
                throw new BusinessException(ExceptionEnum.LOGIN_REJECT.getCode(), ExceptionEnum.LOGIN_REJECT.getMsg());
            }
        }

        InstitutionVO vo = new InstitutionVO();
        BeanUtils.copyProperties(model, vo);
        return vo;
    }


    /**
     * 分页
     *
     * @param params
     * @return
     */
    public PageResult<InstitutionVO> pageAll(Map<String, Object> params) {

        String examVenueStrs = params.containsKey("examVenues") ? params.get("examVenues").toString() : "";
        if (StringUtils.isNotEmpty(examVenueStrs)) {
            params.put("examVenues", examVenueStrs.split(","));
        } else {
            params.remove("examVenues");
        }

        // 数据权限判断
        LoginAppUser currentUser = AuthUtils.getLoginAppUser();

        // 数据权限判断
        List<SysScopePermission> permissions = scopePermissionService.findByUser(currentUser);
        List<SysInstitution> list = new ArrayList<>();

        if (!params.containsKey(CommonConstant.PAGE_CURRENT)) {
            params.put(CommonConstant.PAGE_CURRENT, 1);
        }
        if (!params.containsKey(CommonConstant.PAGE_SIZE)) {
            params.put(CommonConstant.PAGE_SIZE, 20);
        }
        int count = 0;

        //设置分页信息，分别是当前页数和每页显示的总记录数【记住：必须在mapper接口中的方法执行之前设置该分页信息】
        if (MapUtils.getInteger(params, CommonConstant.PAGE_CURRENT) != null && MapUtils.getInteger(params, CommonConstant.PAGE_SIZE) != null)
            PageHelper.startPage(MapUtils.getInteger(params, CommonConstant.PAGE_CURRENT), MapUtils.getInteger(params, CommonConstant.PAGE_SIZE), true);

        if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ALL")).count() > 0) {
            // 全部机构权限
            list = institutionDao.findAll(params);
            count = institutionDao.count(params);
        } else if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ORG")).count() > 0) {
            // 当前及下级
            params.put("organizationId", currentUser.getOrganizationId());
            list = institutionDao.findAll(params);
            count = institutionDao.count(params);
        }

        List<InstitutionVO> result = list.stream().map(t -> {
            InstitutionVO vo = new InstitutionVO();
            BeanUtils.copyProperties(t, vo);

            vo.setExamVenueName(organizationService.getFullName(t.getExamVenue()));

            return vo;
        }).collect(Collectors.toList());


        PageInfo<InstitutionVO> pageInfo = new PageInfo(result);

        return PageResult.<InstitutionVO>builder().data(PageResultData.<InstitutionVO>builder().records(pageInfo.getList()).total(Long.valueOf(count)).pages(pageInfo.getPages()).build()).code(CodeEnum.SUCCESS.getCode()).count(Long.valueOf(count)).build();
    }

    /**
     * 列表
     *
     * @param params
     * @return
     */
    public List<InstitutionVO> findAll(Map<String, Object> params) {
        Integer loadAll = MapUtils.getInteger(params, "loadAll");

        LoginAppUser currentUser = AuthUtils.getLoginAppUser();

        List<SysInstitution> list = new ArrayList<>();

        String examVenueStrs = params.containsKey("examVenues") ? params.get("examVenues").toString() : "";
        if (StringUtils.isNotEmpty(examVenueStrs)) {
            params.put("examVenues", examVenueStrs.split(","));
        } else {
            params.remove("examVenues");
        }


        if (currentUser == null || (loadAll != null && 1 == loadAll)) {
            list = institutionDao.findAll(params);
        } else {
            // 数据权限判断
            List<SysScopePermission> permissions = scopePermissionService.findByUser(currentUser);
            if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ALL")).count() > 0) {
                // 全部机构权限
                list = institutionDao.findAll(params);
            } else if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ORG")).count() > 0) {
                // 当前及下级
                params.put("organizationId", currentUser.getOrganizationId());
                list = institutionDao.findAll(params);
            }
        }

        List<InstitutionVO> result = list.stream().map(t -> {
            InstitutionVO vo = new InstitutionVO();
            BeanUtils.copyProperties(t, vo);

            vo.setExamVenueName(organizationService.getFullName(t.getExamVenue()));

            return vo;
        }).collect(Collectors.toList());


        return result;

    }

    @Override
    public Integer count(Map<String, Object> params) {
        String examVenueStrs = params.containsKey("examVenues") ? params.get("examVenues").toString() : "";
        if (StringUtils.isNotEmpty(examVenueStrs)) {
            params.put("examVenues", examVenueStrs.split(","));
        } else {
            params.remove("examVenues");
        }
        int count = institutionDao.count(params);

//        // 数据权限判断
//        LoginAppUser currentUser = AuthUtils.getLoginAppUser();
//
//        // 数据权限判断
//        List<SysScopePermission> permissions = scopePermissionService.findByUser(currentUser);
//
//        int count = 0;
//
//        if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ALL")).count() > 0) {
//            // 全部机构权限
//            count = institutionDao.count(params);
//        } else if (CollectionUtils.isNotEmpty(permissions) && permissions.stream().filter(t -> t.getItemType().equalsIgnoreCase("ORG")).count() > 0) {
//            // 当前及下级
//            params.put("organizationId", currentUser.getOrganizationId());
//            count = institutionDao.count(params);
//        }

        return count;

    }
}
